package dao

import (
	"OJCenter/dao/mysql"
	"OJCenter/dao/redis"
	"OJCenter/global"
	"OJCenter/idl"
	"errors"
	"strconv"
	"xorm.io/xorm"
)

const ContestDetailInfoPre = "cd:"

type ContestDetailInfo struct {
	mysql *mysql.MysqlDao
	redis *redis.RedisDao
}

func NewContestDetailInfo() (*ContestDetailInfo, error) {
	m, err := mysql.NewMysqlDao()
	if err != nil {
		return nil, err
	}
	r, err := redis.NewRedisDao()
	if err != nil {
		return nil, err
	}
	return &ContestDetailInfo{
		mysql: m,
		redis: r,
	}, nil
}

func (u *ContestDetailInfo) GetContestDetailPidsFromCache(cid int64) (*[]int64, error) {
	pros, err := u.redis.SGet(ContestDetailInfoPre + strconv.Itoa(int(cid)))
	rets := make([]int64, len(pros))
	for i, pro := range pros {
		tmp, _ := strconv.Atoi(pro)
		rets[i] = int64(tmp)
	}
	if err != nil {
		global.Logger.Errorf("GetContestDetailPidsFromCache failed,err:%v", err)
		return nil, err
	}
	return &rets, nil
}

func (u *ContestDetailInfo) GetContestDetailInfosFromData(cid int64) (*[]idl.ContestDetailInfo, error) {
	var details []idl.ContestDetailInfo
	err := u.mysql.Orm.Where("cid=?", cid).Find(&details)
	if err != nil {
		return nil, err
	}
	pros := make([]string, len(details))
	for i, ret := range details {
		pros[i] = strconv.Itoa(int(ret.Pid))
	}
	_, err = u.redis.SSet(ContestDetailInfoPre+strconv.Itoa(int(cid)), pros...)
	if err != nil {
		global.Logger.Errorf("ContestDetail load redis failed,err:%v", err)
	}

	return &details, nil
}

func (u *ContestDetailInfo) DeleteContestDetailInfo(info *idl.ContestDetailInfo) error {
	if info == nil {
		return errors.New("info is nil")
	}
	_, err := u.redis.SDel(ContestDetailInfoPre+strconv.Itoa(int(info.Cid)), strconv.Itoa(int(info.Pid)))
	if err != nil {
		global.Logger.Errorf("ContestDetail load redis failed,err:%v", err)
	}
	cond := make(map[string]interface{})
	if info.Pid != 0 {
		cond["pid"] = info.Pid
	}
	if info.Cid != 0 {
		cond["cid"] = info.Cid
	}
	sum, err := u.mysql.DeleteInfos("contest_detail_info", &cond)
	if err != nil || sum == 0 {
		return errors.New("delete ContestDetail failed")
	}
	return nil
}

func (u *ContestDetailInfo) UpdateContestDetailInfo(info map[string]interface{}) error {
	if info == nil {
		return errors.New("info is nil")
	}
	_, err := u.redis.SDel(ContestDetailInfoPre+strconv.Itoa(int(info["cid"].(int64))), strconv.Itoa(int(info["cid"].(int64))))
	if err != nil {
		global.Logger.Errorf("ContestDetail load redis failed,err:%v", err)
	}
	cond := make(map[string]interface{})
	cond["cid"] = info["cid"].(int64)
	cond["pid"] = info["pid"].(int64)
	sum, err := u.mysql.UpdateInfos("contest_detail_info", &info, &cond)
	if err != nil || sum == 0 {
		return errors.New("update ContestDetail failed")
	}
	return nil
}

func (u *ContestDetailInfo) InsertContestDetailInfo(info *idl.ContestDetailInfo) error {
	ContestDetail, err := u.GetContestDetailInfosFromData(info.Cid)
	if err != nil {
		return err
	}
	sum, err := u.mysql.InsertInfos("contest_detail_info", ContestDetail)
	if err != nil || sum == 0 {
		return err
	}
	return nil
}

func (u *ContestDetailInfo) IsContestDetailInfoHasP(cid int64, pid int64) (bool, error) {
	var cdInfo []idl.ContestDetailInfo
	has, err := u.mysql.Orm.Where("cid=? AND pid=?", cid, pid).Get(&cdInfo)
	if err != nil && err != xorm.ErrNotExist {
		return false, err
	}
	return has, nil
}

func (u *ContestDetailInfo) SelectContestDetail(info *idl.ContestDetailInfo) (*[]idl.ContestDetailInfo, error) {
	var rets []idl.ContestDetailInfo
	err := u.mysql.Orm.Table("contest_detail_info").Find(&rets, info)
	if err != nil {
		return nil, err
	}
	return &rets, nil
}
